/*****************************************************************************/
/*                                                                           */
/*    Domino Operation System Driver Module                                  */
/*                                                                           */
/*    Copyright (C) 2005 Laszlo Arvai                                        */
/*                                                                           */
/*    ------------------------------------------------------------------     */
/*    drvPWMSound.c - PWM based Sound Output Driver                          */
/*****************************************************************************/

///////////////////////////////////////////////////////////////////////////////
// Includes
#include <avr/io.h>
#include <avr/interrupt.h>
#include "sndWave.h"
#include "krnlResourceFile.h"

///////////////////////////////////////////////////////////////////////////////
// Module local variables
static volatile dosHandle l_position = 0;
static volatile dosWord l_remaining = 0;
static volatile dosByte l_divisor = 0;
static dosROMAddress l_wave_resource_address = 0;
    

///////////////////////////////////////////////////////////////////////////////
// Initialize wave device
void sndInitWaveDevice(void)
{
	// Use Timer0 for wave output
	OCR0 = 0x80;
	DDRB |= _BV(PB4);
	TCCR0 = _BV(WGM01) | _BV(WGM00) | _BV(COM01) | _BV(CS00);

	// init wave resource address
  l_wave_resource_address = krnlGetResourceAddress( 0x45564157ul );
}

///////////////////////////////////////////////////////////////////////////////
// Play wave
dosBool sndStartWaveOut( dosHandle in_wave_handle )
{
	dosROMAddress address;

	// stop wave out
	TIMSK &= ~_BV(TOIE0);

	// get resource data

	// if no wave chunk in the resource file
	if( l_wave_resource_address == 0 )
		return dosFalse;

	address = l_wave_resource_address + in_wave_handle;

	// check format
	if( dosROMReadByte( address++ ) != 1 )
		return dosFalse;

	// load size
	l_remaining = (dosWord)(dosROMReadDWord( address ) );

	// address of wave data
	l_position = address + sizeof( dosDWord );

	l_divisor = 0;

	// enable interrupt
	TIMSK |= _BV(TOIE0);

	return dosTrue;
}

///////////////////////////////////////////////////////////////////////////////
// Is Wave Out Busy
dosBool sndIsWaveOutBusy(void)
{
	return (l_remaining > 0);
}

///////////////////////////////////////////////////////////////////////////////
// Stop Wave Out
void sndStopWaveOut(void)
{
	l_remaining = 0;

	// disable interrupt
	TIFR &= ~_BV(TOV0);
}

///////////////////////////////////////////////////////////////////////////////
// Interrupt handler
SIGNAL(SIG_OVERFLOW0)
{
	// handle divisor
	l_divisor++;

	if( l_divisor	> 8 )
	{
		// send next sample
		l_divisor = 0;

		// stop wave out if no more samples
		if( l_remaining == 0 )
		{
			// restore pwm
			OCR0 = 0x80;
			
			// disable interrupt
			TIFR &= ~_BV(TOV0);
		}
		else
		{
			// send new sample
			OCR0 = dosROMReadWord( l_position );
			l_position++;
			l_remaining--;
		}
	}
}
